package com.platform.modules.alg.alglib.p932;

import java.util.LinkedList;
import java.util.Queue;

public class P932 {
    public String output = "";
    public static final int N = 10;
    boolean bestx[] = new boolean[N];
    Goods goods[] = new Goods[N];
    Integer bestp;
    int W;
    int n;
    int sumw;
    int sumv;

    public String cal(String input) {
        String[] line = input.split("\n");
        String[] words = line[0].split(" ");
        // 物品的个数和背包的容量
        n = Integer.parseInt(words[0]);
        W = Integer.parseInt(words[1]);
        bestp = 0; // bestv 用来记录最优解
        sumw = 0; // sumw 为所有物品的总重量。
        sumv = 0; // sumv为所有物品的总价值
        words = line[1].split(" ");
        for (int i = 1; i <= words.length / 2; i++) { // 输入每个物品的重量和价值,用空格分开
            goods[i].weight = Integer.parseInt(words[2 * i - 2]);
            goods[i].value = Integer.parseInt(words[2 * i - 1]);
            sumw += goods[i].weight;
            sumv += goods[i].value;
        }
        if (sumw <= W) {
            bestp = sumv;
            output = bestp.toString();
            return output;
        }
        bfs();
        output += bestp.toString() + "\n";
        for (int i = 1; i <= n; i++) { // 输出最优解
            if (bestx[i])
                output += i + "  ";
        }
        return output;
    }

    public P932() {
        for (int i = 0; i < goods.length; i++) {
            goods[i] = new Goods();
        }
    }

    int bfs() { // 队列式分支限界法
        int t, tcp, trp, trw; // 当前处理的物品序号t，装入背包物品价值 tcp,剩余容量 trw
        Queue<Node> q = new LinkedList<>(); // 创建一个普通队列(先进先出)
        q.add(new Node(0, sumv, W, 1)); // 压入一个初始节点
        while (!q.isEmpty()) {
            // 定义三个结点型变量
            Node livenode = new Node();
            Node lchild = new Node();
            Node rchild = new Node();
            livenode = q.peek(); // 取出队头元素作为当前扩展结点 livenode
            q.poll(); // 队头元素出队
            t = livenode.id; // 当前处理的物品序号
            // 搜到最后一个物品的时候不需要往下搜索
            // 如果当前的背包没有剩余容量(已经装满)了，不再扩展
            if (t > n || livenode.rw == 0) {
                if (livenode.cp >= bestp) { // 更新最优解和最优值
                    for (int i = 1; i <= n; i++)
                        bestx[i] = livenode.x[i];
                    bestp = livenode.cp;
                }
                continue;
            }
            if (livenode.cp + livenode.rp < bestp) // 判断当前结点是否满足限界条件，如果不满足不再扩展
                continue;
            tcp = livenode.cp; // 当前背包中的价值
            trp = livenode.rp - goods[t].value; // 不管当前物品装入与否，剩余价值都会减少。
            trw = livenode.rw; //背包剩余容量
            if (trw >= goods[t].weight) { //扩展左孩子，满足约束条件，可以放入背包
                lchild.rw = trw - goods[t].weight;
                lchild.cp = tcp + goods[t].value;
                lchild = new Node(lchild.cp, trp, lchild.rw, t + 1);
                for (int i = 1; i < t; i++) // 复制以前的解向量
                    lchild.x[i] = livenode.x[i];
                lchild.x[t] = true;
                if (lchild.cp > bestp) // 比最优值大才更新
                    bestp = lchild.cp;
                q.add(lchild); // 左孩子入队
            }
            if (tcp + trp >= bestp) {//扩展右孩子,满足限界条件，不放入背包
                rchild = new Node(tcp, trp, trw, t + 1);
                for (int i = 1; i < t; i++)//复制以前的解向量
                    rchild.x[i] = livenode.x[i];
                rchild.x[t] = false;
                q.add(rchild); // 右孩子入队
            }
        }
        return bestp;// 返回最优值
    }
}

// 定义结点。每个节点来记录当前的解。
class Node {
    int cp; // cp 为当前装入背包的物品总价值
    int rp; // rp为剩余物品的总价值
    int rw; // 剩余容量
    int id; // 物品号
    boolean x[] = new boolean[P932.N]; //解向量

    Node() {
    }

    Node(int _cp, int _rp, int _rw, int _id) {
        cp = _cp;
        rp = _rp;
        rw = _rw;
        id = _id;
    }
}

// 物品
class Goods {
    int weight; //重量
    int value; //价值
}
